package code.framework.android.util;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Contains essential facade objects for batches control. int poolSize int
 * closeAndWaitInterval
 */
public class ExecutorFacade {
	private class MyThreadFactory implements ThreadFactory {
		@Override
		public Thread newThread(Runnable runnable) {
			Thread thread = new Thread(runnable);
			thread
					.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
			return thread;
		}
	};

	private class MyUncaughtExceptionHandler implements
			Thread.UncaughtExceptionHandler {
		public void uncaughtException(Thread thread, Throwable throwable) {
			logger.error("uncaughtException", throwable);
		}
	};

	private static final int POOL_SIZE = 4;
	private static final int CLOSE_AND_WAIT_INTERVAL = 100;

	// private int poolSize = POOL_SIZE;
	private int closeAndWaitInterval = CLOSE_AND_WAIT_INTERVAL;

	protected ExecutorService executorService;

	protected MyUncaughtExceptionHandler myUncaughtExceptionHandler;

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	public ExecutorFacade() {
		this(POOL_SIZE);
	}

	public ExecutorFacade(int poolSize) {
		executorService = Executors.newFixedThreadPool(poolSize,
				new MyThreadFactory());
	}

	/**
	 * As executorService.submit()
	 * 
	 * @param Callable
	 *            - object waiting to be called in batch
	 * @return Future - pending result
	 */
	public Future<?> submit(Callable<?> callable) {
		return executorService.submit(callable);
	}

	/**
	 * As executorService.submit()
	 * 
	 * @param Runnable
	 *            - object waiting to be called in batch
	 */
	public void submit(Runnable runnable) {
		executorService.submit(runnable);
	}

	/**
	 * As executorService.shutdown()
	 */
	public void close() {
		executorService.shutdown();
	}

	/**
	 * Shutdown the executorSevice and wait for all batches finished
	 * 
	 * @throws InterruptedException
	 */
	public void closeAndWait() throws InterruptedException {
		executorService.shutdown();
		while (!executorService.isTerminated()) {
			synchronized (this) {
				super.wait(closeAndWaitInterval);
			}
		}
	}

	// public void setPoolSize(int poolSize) {
	// this.poolSize = poolSize;
	// }

	public void setCloseAndWaitInterval(int closeAndWaitInterval) {
		this.closeAndWaitInterval = closeAndWaitInterval;
	}

}
